#include "global.h"
#include "CEngine.h"
#include "CGame.h"

CGame m_Game;
CGUI m_GUI;
map<int,CRoom *> m_Rooms;
bool m_On;
CRoom *m_Room;
map<string,vector<CObject *> > m_MasterObjects;

int TotalTurns=0;

CObject::CObject()
{
  Clear();
  m_MasterNum=GenerateID();
};
CObject::~CObject()
{
  Clear();
};

void CObject::Run()
{
  int i;
  for(i=0;i<AI.size();i++)
    AI[i](this,"run");
};
void CObject::Input(int e)
{
};
void CObject::Draw(int p)
{
  int i;
  if(m_DrawPass!=p)
    return;
  if(m_Y-(Player->m_Y-7)>14||m_X-(Player->m_X-20)>40)
    return;
  mvaddch(m_Y-(Player->m_Y-7),m_X-(Player->m_X-20),m_Tile);
  if(m_Type==5)
    m_Game.m_SeenEnemies++;
  for(i=0;i<AI.size();i++)
    AI[i](this,"draw");
};
void CObject::Clear()
{
  m_X = m_Y = m_Tile = m_Type = m_DrawPass = 0;
  m_Collide = m_Shown = false;
  m_Clear = true;
  m_Die=false;
  Name="Object";
  Flags.clear();
  Vars.clear();
  Strings.clear();
  AI.clear();
};
CObject *CObject::SpawnSelf(int x,int y)
{
  int i;
  CObject *o;
  o = new CObject();
  o->m_X = x;
  o->m_Y = y;
  o->m_Collide = m_Collide;
  o->m_Shown = m_Shown;
  o->m_Clear = m_Clear;
  o->m_Type = m_Type;
  o->m_Tile = m_Tile;
  o->Flags = Flags;
  o->Vars = Vars;
  o->Strings = Strings;
  o->AI = AI;
  o->m_MasterNum = m_MasterNum;
  o->m_Amount = m_Amount;
  for(i=0;i<o->AI.size();i++)
    o->AI[i](o,"init");
  m_Room->m_Objects.push_back(o);
  return o;
};

bool CObject::CollideMap(int x,int y)
{
  if(x<0||y<0||x>MAPXSIZE-1||y>MAPYSIZE-1)
    return true;
  if(m_Room->m_Map[x][y][1]==1)
    return true;
  return false;
};
CObject *CObject::CollideObject(int n)
{
  CObject *o;
  int i,j,k;
  j = m_Room->m_Objects.size();
  k = 0;
  for(i=0;i<j;i++)
    {
      o = m_Room->m_Objects[i];
      if(o!=this&&o->m_X==m_X&&o->m_Y==m_Y)
	{
	  if(k==n)
	    return o;
	  k++;
	};
    };
  return NULL;
};
int CObject::GetType()
{
  return m_Type;
};

void CObject::Die()
{
  int i;
  for(i=0;i<AI.size();i++)
    AI[i](this,"die");
  m_Die=true;
  return;
};
void CObject::Message(int m)
{
  char buf[255];
  string s;
  int i;
  sprintf(buf,"Message%d",m);
  s = buf;
  for(i=0;i<AI.size();i++)
    AI[i](this,s);
};
void CObject::Message(string m)
{
  int i;
  for(i=0;i<AI.size();i++)
    AI[i](this,m);
};
CRoom::CRoom()
{
  m_RoomNum = m_Rooms.size();
  m_Rooms[m_RoomNum]=this;
  Clear();
};
CRoom::CRoom(int n)
{
  m_RoomNum=n;
  m_Rooms[n]=this;
  Clear();
};
CRoom::~CRoom()
{
  Clear();
};

void CRoom::Run()
{
  int i;
  for(i=0;i<m_Objects.size();i++)
    if(m_Objects[i]->m_Die)
      {
	delete(m_Objects[i]);
	m_Objects.erase(m_Objects.begin()+i);
	//mvprintw(0,0,"Here\n");
	refresh();
	//getch();
	i--;
      }
    else
      m_Objects[i]->Run();
};
void CRoom::Input(int e)
{
  int i;
  for(i=0;i<m_Objects.size();i++)
    m_Objects[i]->Input(e);
};
void CRoom::Draw()
{
  CObject *o,*o2;
  int i,j,k,n;
  float x,y,l,x2,y2;
  bool br;
  map<string,bool> seen;
  o = m_Game.GetPlayer();
  for(i=0;i<MAPXSIZE;i++)
    for(j=0;j<MAPYSIZE;j++)
      if(m_Map[i][j][2]==1)
	m_Map[i][j][2] = 2;
  for(i=0;i<360;i++)
    {
      x=o->m_X+0.5f;
      y=o->m_Y+0.5f;
      x2 = cos((float)i*0.01745f);
      y2 = sin((float)i*0.01745f);
      for(j=0;j<40;j++)
	{
	  if(x<0||y<0||x>MAPXSIZE||y>MAPYSIZE)
	    break;
	  m_Map[(int)x][(int)y][2] = 1;
	  if(m_Map[(int)x][(int)y][1]!=0)
	    break;
	  br = false;
	  for(n=0;n<m_Objects.size();n++)
	    {
	      o2 = (CObject *)m_Objects[n];
	      if(o2->m_X==(int)x&&o2->m_Y==(int)y&&o2!=o&&!o2->m_Clear&&(o->m_X!=o2->m_X||o->m_Y!=o2->m_Y))
		br = true;
	    };
	  if(br==true)
	    break;
	  x+=x2;
	  y+=y2;
	};
    };
  clear();
  //The third array of map: 0 - never seen 1 - seen now 2 - seen before 3 - Don't update until seen again. Used for objects.
  for(i=Player->m_X-20;i<Player->m_X+20;i++)
    for(j=Player->m_Y-7;j<Player->m_Y+7;j++)
      if(j>-1&&i>-1&&j<25&&i<80)
	if(m_Map[i][j][2]!=0)
	  {
	    if(m_Map[i][j][3]!=0)
	      attron(COLOR_PAIR(m_Map[i][j][3]));
	    else
	      attron(COLOR_PAIR(1));
	    if(m_Map[i][j][2]==2)
	      attron(COLOR_PAIR(2));
	    mvaddch(j-(Player->m_Y-7),i-(Player->m_X-20),m_Map[i][j][0]);
	  }
	else
	  mvaddch(j-(Player->m_Y-7),i-(Player->m_X-20),' ');
  attron(COLOR_PAIR(1));
  j = m_Objects.size();
  m_Game.m_SeenEnemies = 0;
  n=0;
  for(k=0;k<4;k++)
    for(i=0;i<j;i++)
      {
	o = m_Objects[i];
	if(m_Map[o->m_X][o->m_Y][2]==1)
	  {
	    o->Draw(k);
	    o->Name[0]=toupper(o->Name.c_str()[0]);
	    if(seen[o->Name]!=true&&o->Name!="Object")
	      {
		seen[o->Name]=true;
		mvprintw(10+n,40,"%c - %s\n",o->m_Tile,o->Name.c_str());
		n++;
	      };
	  };
      };
  attron(COLOR_PAIR(1));
  seen.clear();
};
void CRoom::CenterCamera(int x,int y)
{
	m_CameraX = 0;//x-MAPXSIZE/2;
	m_CameraY = 0;//y-MAPYSIZE/2;
};
void CRoom::Clear()
{
	int i,j;
	for(i=0;i<MAPXSIZE;i++)
		for(j=0;j<MAPYSIZE;j++)
			m_Map[i][j][0] = m_Map[i][j][1] = m_Map[i][j][2] = m_Map[i][j][3] = 0;
	while(m_Objects.size()>0)
	{
		if(m_Objects[0]!=NULL)
			delete((CObject *)m_Objects[0]);
		m_Objects.erase(m_Objects.begin());
	};
	CenterCamera(0.0f,0.0f);
};

CGUI::CGUI()
{
	ClearBottom();
	ClearTop();
};
CGUI::~CGUI()
{
	ClearBottom();
	ClearTop();
};

void CGUI::Draw()
{
  ClearTop();
  DrawBottom();
  DrawTop();
  ClearBottom();
};
void CGUI::DrawBottom()
{
  int i,j,x,x2;
  j = m_BottomText.size();
  x = 0;
  for(i=0;i<j;i++)
    {
      x2=x+m_BottomText[i].size();
      if(x2<80)
	mvprintw(1,40,m_BottomText[i].c_str());
      else
	return;
      x=x2;
    };
};
void CGUI::DrawTop()
{
  int i;
  for(i=0;i<9;i++)
    if(i<m_TopText.size())
      {
	m_TopText[i][0] = toupper(m_TopText[i][0]);
	mvprintw(15+i,1,"%s",m_TopText[i].c_str());
      };
};

void CGUI::ClearBottom()
{
  m_BottomText.clear();
};
void CGUI::ClearTop()
{
  if(m_TopText.size()<8)
    return;
  while(m_TopText.size()>8)
    m_TopText.erase(m_TopText.begin());
};
void CGUI::AddBottom(string s)
{
  m_BottomText.push_back(s);
};
void CGUI::AddTop(string s,bool m)
{
  m_TopText.push_back(s);
};


void Init()
{
  initscr();
  cbreak();
  noecho();
  nl();
  keypad(stdscr,true);
  srand(time(0));
  start_color();
  init_pair(0, COLOR_WHITE, COLOR_BLACK);
  init_pair(1, COLOR_WHITE, COLOR_BLACK);
  init_pair(2, COLOR_BLUE, COLOR_BLACK);
  init_pair(3, COLOR_RED, COLOR_BLACK);
  init_pair(4, COLOR_GREEN, COLOR_BLACK);
  init_pair(5, COLOR_YELLOW, COLOR_BLACK);
  init_pair(6, COLOR_MAGENTA, COLOR_BLACK);
  init_pair(7, COLOR_CYAN, COLOR_BLACK);
  attron(COLOR_PAIR(1));
  
  m_On = true;
  m_Game.Load();
};
void Exit()
{
  endwin();
  m_On = false;
};

bool Run()
{ 
  Input();
  m_Room->Run();
  Draw();
  TotalTurns++;
  return m_On;
};
void Input()
{
  int e;
  flushinp();
  e = getch();
  switch(e)
    {
    case 'q':
      m_On = false;
      break;
    };
  m_Room->Input(e);
};
void Draw()
{
  m_Room->Draw();
  m_GUI.Draw();
  refresh();
};
